﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Openlab.Tools.CodeGender.Classes;
using Openlab.Tools.CodeGender.Funtions;
using Openlab.Tools.CodeGender.StoredProcedures;
using CarolLib.Tools.CodeGender.Coder.Classes;

namespace Openlab.Tools.CodeGender
{
    public partial class frmGeCodeFiles : Form
    {

        Dictionary<string, string> tables;
        public frmMain mainForm;
        private CodeOption codeOption;

        public frmGeCodeFiles()
        {
            InitializeComponent();
        }

        private void frmDBDocument_Load(object sender, EventArgs e)
        {
            string dbName = DataAccess.GetDatabase();
            tables = DataAccess.GetTablesWithCommaRemark();
            this.cklTables.Items.AddRange(tables.Keys.ToArray());
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void chkAll_CheckedChanged(object sender, EventArgs e)
        {
            for (int i = 0; i < this.cklTables.Items.Count; i++)
            {
                this.cklTables.SetItemChecked(i, chkAll.Checked);
            }
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            int prefix = this.cklTables.CheckedItems[0].ToString().IndexOf('_');

            List<string> tableNames = new List<string>();
            foreach (var item in this.cklTables.CheckedItems)
                tableNames.Add(item.ToString());


            string sql = "";
            foreach (var group in tableNames.GroupBy(s => s.Substring(0, prefix)))
            {
                string dalCode = "";
                string subpath = ckGroupByPrefix.Checked ? "\\" + FormatePreix(group.Key) : "";

                sql += string.Format("-------------{0}----------------\n", group.Key);

                foreach (var tableName in group)
                {

                    codeOption = mainForm.GetCodeOption(tableName);
                    if (ckbCode.Checked && tableName.Contains("_code_"))
                    {
                        continue;
                    }

                    string modelCode = new EntityClass(codeOption).Code;
                    string queryCode = new QueryEntityClass(codeOption).Code;

                    dalCode += GenerateDataAccessCode(codeOption);

                    string bllCode = GenerateManagerCode(codeOption.IdColumn,group.Key);

                    sql += GenerateSqlCode(codeOption, tableName);


                    SaveFile(this.tbPath.Text + "\\Model" + subpath, codeOption.ClassName + ".cs", modelCode);

                    SaveFile(this.tbPath.Text + "\\Model\\Query" + subpath, codeOption.ClassName + "QueryEntity.cs", queryCode);

                    SaveFile(this.tbPath.Text + "\\BLL" + subpath, codeOption.ClassName + "Manager.cs", bllCode);

                    SaveFile(this.tbPath.Text + "\\IBLL" + subpath, "I" + codeOption.ClassName + "Manager.cs", GenerateInterface(codeOption.ClassName, group.Key));

                }

                SaveDataAccessCode(this.tbPath.Text + "\\DAL", dalCode, group.Key, codeOption.ModelNamespaceName, codeOption.DalNamespaceName);

            }

            SaveFile(this.tbPath.Text + "\\SQL", "SP.sql", sql);

            MessageBox.Show("生成成功！");

        }


        private string GenerateInterface(string strClsName,string strGroupKey)
        {
            StringBuilder code = new StringBuilder();
             code.AppendLine("using System;");
             code.AppendLine("using System.Collections.Generic;");
             code.AppendLine("using System.Data;");
             code.AppendLine("using System.Text;");
             code.AppendLine("");
             code.AppendLine("namespace XT2.Service.Contract." + strGroupKey.ToFirstUpper());
             code.AppendLine("{");
             code.AppendWithTabs("public interface I" + strClsName + "Manager",1);
             code.AppendLine("");
             code.AppendWithTabs("{",1);
             code.AppendLine("");
             code.AppendWithTabs("}",1);
             code.AppendLine("");
             code.AppendLine("}");

             return code.ToString();
        }

        protected void SaveFile(string path, string fileName, string content)
        {
            try
            {

                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                if (!File.Exists(path + "\\" + fileName))
                {
                    File.AppendAllText(path + "\\" + fileName, content);
                }
            }

            catch (IOException ex)
            {
                MessageBox.Show(ex.Message, "Simple Editor", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        string GetCHNFieldName(string remarks)
        {
            int idx = remarks.IndexOfAny(new char[] { '(', '（' }, 0);
            return idx == -1 ? remarks : remarks.Substring(0, idx);
        }

        string GetRule(string remarks)
        {
            int idx = remarks.IndexOfAny(new char[] { '(', '（' }, 0);

            return idx == -1 ? string.Empty : remarks.Substring(idx + 1).Replace(")", string.Empty).Replace("）", string.Empty);
        }

        private void btnOutputPath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog save = new FolderBrowserDialog();
            if (save.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.tbPath.Text = save.SelectedPath + "\\";
            }
        }

        #region generate code
        private string GenerateManagerCode(Column idColumn,string key)
        {
            StringBuilder code = new StringBuilder();


            Class manager = new ManagerClass(codeOption);

            manager.NameSpaces.Add("CLFramework.Caching");
            manager.NameSpaces.Add("CLFramework.Data");
            manager.NameSpaces.Add("CLFramework.Infrastructure");
            manager.NameSpaces.Add(codeOption.DalNamespaceName);
            manager.NameSpaces.Add(codeOption.ModelNamespaceName);


            if (ckInterface.Checked)
            {
                manager.NameSpaces.Add("XT2.Service.Contract." + key.ToFirstUpper());
                codeOption.ParentClass = "I" + codeOption.ClassName + "Manager";
            }

            code.AppendLine(manager.Code);

            return code.ToString();
        }

        public string GenerateDataAccessCode(CodeOption option)
        {
            StringBuilder code = new StringBuilder();

            code.AppendLine();

            code.AppendFormat("#region {0}", option.ClassName);
            code.AppendLine();
            code.AppendLine();

            Function funCreateEntity = new CreateEntityDAFunc(option.ClassName, option.CreateEntityStoredProcedureName, option.Columns, option.IdColumn, option.EnableParamCache, option.GetNewAutoGUID);
            code.Append(funCreateEntity.Code);
            code.AppendLine();

            if (option.CreateBatOperation)
            {
                Function batfunCreateEntity = new BatCreateDAFunc(option.ClassName, option.CreateEntityStoredProcedureName + "_Bat", option.Columns, option.IdColumn, option.EnableParamCache, option.GetNewAutoGUID);
                code.Append(batfunCreateEntity.Code);
                code.AppendLine();
            }

            Function funUpdateEntity = new UpdateEntityDAFunc(option.ClassName, option.UpdateEntityStoredProcedureName, option.Columns, option.IdColumn, option.EnableParamCache);
            code.Append(funUpdateEntity.Code);
            code.AppendLine();

            if (option.CreateBatOperation)
            {
                //Function batfunUpdateEntity = new BatCreateDAFunc(option.ClassName, option.UpdateEntityStoredProcedureName + "_Bat", option.Columns, option.IdColumn, option.EnableParamCache);
                //code.Append(batfunUpdateEntity.Code);
                //code.AppendLine();
            }

            Function funDeleteEntity = new DeleteEntityDAFunc(option.ClassName, option.DeleteEntityStoredProcedureName, option.IdColumn);
            code.Append(funDeleteEntity.Code);
            code.AppendLine();

            if (option.WithTrans)
            {
                Function funCreateEntityT = new CreateEntityDAFunc(option.ClassName, option.CreateEntityStoredProcedureName, option.Columns, option.IdColumn, option.EnableParamCache, option.GetNewAutoGUID, true);
                code.Append(funCreateEntityT.Code);
                code.AppendLine();

                Function batfunCreateEntityT = new BatCreateDAFunc(option.ClassName, option.CreateEntityStoredProcedureName, option.Columns, option.IdColumn, option.EnableParamCache, option.GetNewAutoGUID, true);
                code.Append(batfunCreateEntityT.Code);
                code.AppendLine();

                Function funUpdateEntityT = new UpdateEntityDAFunc(option.ClassName, option.UpdateEntityStoredProcedureName, option.Columns, option.IdColumn, option.EnableParamCache, true);
                code.Append(funUpdateEntityT.Code);
                code.AppendLine();

                Function funDeleteEntityT = new DeleteEntityDAFunc(option.ClassName, option.DeleteEntityStoredProcedureName, option.IdColumn, true);
                code.Append(funDeleteEntityT.Code);
                code.AppendLine();
            }

            Function fun1 = new GetEntityIdsDAFunc(option.ClassName, option.GetEntityIdsStoredProcedureName, option.IdColumn);
            code.Append(fun1.Code);
            code.AppendLine();

            Function fun2 = new GetEntitiesDAFunc(option.ClassName, option.GetEntitiesStoredProcedureName, option.IdColumn);
            code.Append(fun2.Code);
            code.AppendLine();

            code.AppendLine();
            code.AppendFormat("#endregion");

            return code.ToString();
        }



        public string GenerateSqlCode(CodeOption option, string tablename)
        {
            Table table = new Table(tablename);
            StringBuilder sql = new StringBuilder();

            StoredProcedure sqlCreateEntitiy = new CreateEntitySP(option.CreateEntityStoredProcedureName, option.Author, option.Columns, option.IdColumn, table, option.GetNewAutoGUID);
            sql.AppendLine(sqlCreateEntitiy.Sql);
            sql.AppendLine();

            StoredProcedure sqlUpdateEntitiy = new UpdateEntitySP(option.UpdateEntityStoredProcedureName, option.Author, option.Columns, option.IdColumn, table);
            sql.AppendLine(sqlUpdateEntitiy.Sql);
            sql.AppendLine();

            if (option.CreateBatOperation)
            {
                StoredProcedure sqlCreateEntitiys = new BatCreateEntity(option.CreateEntityStoredProcedureName + "_Bat", option.Author, option.Columns, option.IdColumn, table, option.GetNewAutoGUID);
                sql.AppendLine(sqlCreateEntitiys.Sql);
                sql.AppendLine();

                StoredProcedure sqlUpdateEntitiys = new BatUpdateEntitySP(option.UpdateEntityStoredProcedureName + "_Bat", option.Author, option.Columns, option.IdColumn, table);
                sql.AppendLine(sqlUpdateEntitiys.Sql);
                sql.AppendLine();
            }

            StoredProcedure sqlDeleteEntitiy = new DeleteEntitySP(option.DeleteEntityStoredProcedureName, option.Author, option.IdColumn, table);
            sql.AppendLine(sqlDeleteEntitiy.Sql);
            sql.AppendLine();

            StoredProcedure sqlGetIds = new GetIdsSP(option.GetEntityIdsStoredProcedureName, option.Author, option.IdColumn, table);
            sql.AppendLine(sqlGetIds.Sql);
            sql.AppendLine();

            StoredProcedure sqlGetEntities = new GetEntitiesSP(option.GetEntitiesStoredProcedureName, option.Author, option.Columns, option.IdColumn, table);
            sql.AppendLine(sqlGetEntities.Sql);
            sql.AppendLine();

            return sql.ToString();
        }

        
        public string GenerateInterfaceCode()
        {
            return null;
        }

        #endregion

        private string FormatePreix(string preix)
        {
            return preix[0].ToString().ToUpper() + preix.Substring(1);
        }

        private void SaveDataAccessCode(string path, string content, string preix, string modelNameSpace, string dalNameSpace)
        {
            string className = FormatePreix(preix) + "DataProvider";
            int tabCount = 1;
            StringBuilder fileContent = new StringBuilder();
            StringBuilder code = new StringBuilder();
            code.AppendLine("using System;");
            code.AppendLine("using System.Collections.Generic;");
            code.AppendLine("using System.Linq;");
            code.AppendLine("using System.Text;");
            code.AppendLine("using System.Data;");
            code.AppendLine("using System.Data.SqlClient;");
            code.AppendLine("using CLFramework.Data;");
            code.AppendLine("using System.Configuration;");
            code.AppendLineFormat("using {0};", modelNameSpace);

            code.AppendLine();

            code.AppendLineFormatWithTabs("namespace {0}", 0, dalNameSpace);
            code.AppendLine("{");

            code.AppendLineWithTabs("/// <summary>", tabCount);
            code.AppendLineFormatWithTabs("/// {0}", tabCount, FormatePreix(preix) + "模块数据访问类");
            code.AppendLineWithTabs("/// </summary>", tabCount);

            code.AppendLineFormatWithTabs("public {1} class {0}: {2}", tabCount, className, "sealed", "DataProviderBase");
            code.AppendLineWithTabs("{", tabCount);

            code.AppendLineWithTabs("#region Singleton", tabCount + 1);
            code.AppendLineWithTabs("", tabCount + 1);
            code.AppendLineWithTabs(string.Format("public static {0} Instance",className), tabCount + 1);
            code.AppendLineWithTabs("{", tabCount + 1);
            code.AppendLineWithTabs("get", tabCount + 2);
            code.AppendLineWithTabs("{", tabCount + 2);
            code.AppendLineWithTabs("if (_dataProvider == null)", tabCount + 3);
            code.AppendLineWithTabs(string.Format("_dataProvider = new {0}();", className), tabCount + 4);
            code.AppendLineWithTabs(" return _dataProvider;", tabCount + 3);
            code.AppendLineWithTabs("}", tabCount + 2);
            code.AppendLineWithTabs("}", tabCount + 1);
            code.AppendLineWithTabs("", tabCount + 1);
            code.AppendLineWithTabs(string.Format(@"private {0}()", className), tabCount + 1);
            code.AppendLineWithTabs("{", tabCount + 1);
            code.AppendLineWithTabs("try", tabCount + 2);
            code.AppendLineWithTabs("{", tabCount + 2);
            code.AppendLineWithTabs(string.Format(@"connectionString = ConfigurationManager.ConnectionStrings[""{0}""].ConnectionString;", "xTrans2ConnectString"), tabCount + 3);
            code.AppendLineWithTabs("}", tabCount + 2);
            code.AppendLineWithTabs("catch (Exception e)", tabCount + 2);
            code.AppendLineWithTabs("{", tabCount + 2);
            code.AppendLineWithTabs("throw e;", tabCount + 3);
            code.AppendLineWithTabs("}", tabCount + 2);
            code.AppendLineWithTabs("}", tabCount + 1);
            code.AppendLine();
            code.AppendLineWithTabs(string.Format("private static {0} _dataProvider;",className), tabCount + 1);
            
            code.AppendLineWithTabs("#endregion ", tabCount + 1);
            code.AppendLine();

            code.AppendLineWithTabs("#region Conn", tabCount + 1);
            code.AppendLineWithTabs("", tabCount + 1);
            code.AppendLineWithTabs("protected override SqlConnection GetSqlConnection()", tabCount + 1);
            code.AppendLineWithTabs("", tabCount + 1);
            code.AppendLineWithTabs("{", tabCount + 1);
            code.AppendLineWithTabs("return new SqlConnection(connectionString);", tabCount + 2);
            code.AppendLineWithTabs("}", tabCount + 1);
            code.AppendLineWithTabs("private static string connectionString;", tabCount + 1);
            code.AppendLineWithTabs("#endregion", tabCount + 1);

            code.AppendLineWithTabs("", tabCount + 1);

            code.AppendLine(content.IncreaseIndent(tabCount + 1));

            code.AppendLineWithTabs("}", tabCount);
            code.AppendLine("}");

            SaveFile(path, FormatePreix(preix) + "DataProvider.cs", code.ToString());

        }

    }
}